//
//  ZHBaseAVPlayerView.m
//  AVPlayer
//
//  Created by 正合适 on 2017/10/20.
//  Copyright © 2017年 正合适. All rights reserved.
//

#import "ZHBaseAVPlayerView.h"
#import <AVFoundation/AVFoundation.h>

@interface ZHBaseAVPlayerView ()
/**播放界面*/
@property (nonatomic, strong) AVPlayerLayer *playerLayer;
/**player*/
@property (nonatomic, strong) AVPlayer *avplayer;
///**palyerItem*/
//@property (nonatomic, copy) AVPlayerItem *avplayerItem;
/**播放链接*/
@property (nonatomic, copy) NSString *url;
///**视频资源*/
//@property (nonatomic, strong) AVURLAsset *urlAsset;
/**视频播放配置文件*/
@property (nonatomic, strong) ZHBaseAVPlayerConfiguration *configuration;
/**视频资源加载完成的占位图*/
@property (nonatomic, strong) UIImageView *placeholderImgView;
/**播放进度监听*/
@property (nonatomic, strong) id progressObserver;
/**是否为用户手动暂停视频*/
@property (nonatomic, assign) BOOL isUserPause;
/**seekTime*/
@property (nonatomic, assign) float seekTime;
@end

@implementation ZHBaseAVPlayerView
#pragma mark - ---------- 生命周期 ----------
- (instancetype)initWithFrame:(CGRect)frame configuration:(ZHBaseAVPlayerConfiguration *)configuration {
    self = [super initWithFrame:frame];
    if (self) {
        _configuration = configuration;
        [self main];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    return [self initWithFrame:frame configuration:nil];
}

- (void)dealloc {
    [self removeObserversAndNotify];
    [_avplayer removeTimeObserver:_progressObserver];
    NSLog(@"---------- ZHBaseAVPlayerView-视屏播放控件被释放 ----------");
}

#pragma mark - ---------- 其他方法 ----------
#pragma mark - main入口
- (void)main {
    [self defaultDatas];
    [self createUI];
}

#pragma mark - 初始化参数
- (void)defaultDatas {
    _seekTime = 0;
    _isUserPause = NO;
}

#pragma mark - 初始化界面
- (void)createUI {
    self.backgroundColor = _configuration.playerColor?_configuration.playerColor:[UIColor whiteColor];
    AVLayerVideoGravity type;
    switch (_configuration.grivatyType) {
        case gravityResizeAspect:
            type = AVLayerVideoGravityResizeAspect;
            break;
        case gravityResizeAspectFill:
            type = AVLayerVideoGravityResizeAspectFill;
            break;
        case gravityResize:
            type = AVLayerVideoGravityResize;
            break;
        default:
            type = AVLayerVideoGravityResizeAspect;
            break;
    }
    _playerLayer = [[AVPlayerLayer alloc] init];
    _playerLayer.frame = self.bounds;
    _playerLayer.videoGravity = type;
    _playerLayer.backgroundColor = _configuration.playerLayerColor?_configuration.playerLayerColor.CGColor:[UIColor whiteColor].CGColor;
    [self.layer addSublayer:_playerLayer];
    
}

- (void)layoutSubviews {
    _playerLayer.frame = self.bounds;
}

#pragma mark - 初始化播放器
- (void)createPlayer {
    AVURLAsset *urlAssect = [[AVURLAsset alloc] initWithURL:[NSURL URLWithString:_url] options:nil];
    AVPlayerItem *avplayerItem = [[AVPlayerItem alloc] initWithAsset:urlAssect];
    if (!_avplayer) {
        _avplayer = [[AVPlayer alloc] initWithPlayerItem:avplayerItem];
        
    } else {
        // 切换视频
        [self removeObserversAndNotify];
        [_avplayer replaceCurrentItemWithPlayerItem:avplayerItem];
    }
    _playerLayer.player = _avplayer;
    [self addObservers];
    [self loadItemStatus:playerItemLoad_Begin totalTime:0.0];
}

#pragma mark - 加载视频资源
- (void)loadVideoWithUrl:(NSString *)url {
    if (url.length == 0) {
        return;
    }
    _url = url;
    [self createPlayer];
}

#pragma mark - 添加监听
- (void)addObservers {
    // 观察播放状态
    [_avplayer.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    // 监听视频缓存状态
    [_avplayer.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    // 监听播放状态
    [_avplayer addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackStalledAction) name:AVPlayerItemPlaybackStalledNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playCompleteAction) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}

#pragma mark - 移除监听和通知
- (void)removeObserversAndNotify {
    [_avplayer.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    [_avplayer.currentItem removeObserver:self forKeyPath:@"status"];
    [_avplayer removeObserver:self forKeyPath:@"rate"];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - 视频播放
- (void)play {
    if (self.placeholderImgView.hidden == NO) self.placeholderImgView.hidden = YES;
    _isUserPause = NO;
    [_avplayer play];
}

#pragma mark - 暂停
- (void)pause {
    _isUserPause = YES;
    [_avplayer pause];
}

#pragma mark - 观察者的实现
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"status"]) {
        // item资源播放状态
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        [self dealPlayerStatusWith:status];
    } else if ([keyPath isEqualToString:@"rate"]) {
        // 播放状态
        int rate = [[change objectForKey:@"new"] intValue];
        [self playOrPause:rate];
    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        // 视频缓冲
        NSTimeInterval timeRange = [self availableLoadedTime];
        [self videoBufferTime:timeRange];
        if (!_isUserPause) {
            // 当用户未手动暂停，因为缓存不足以导致的播放暂停，需要在缓存足够时继续播放
            if (timeRange > [self translateCurrentPlayProgress]+5) {
            }
        }
    }
}

#pragma mark - 播放状态的监听的action
- (void)dealPlayerStatusWith:(AVPlayerStatus)status {
    switch (status) {
        case AVPlayerStatusReadyToPlay:
            // 视频加载成功
            [self loadItemStatus:playerItemLoad_Success totalTime:_avplayer.currentItem.duration.value/_avplayer.currentItem.duration.timescale];
            [self loadVideoResourceSuccess];
            break;
        case AVPlayerStatusFailed:
            [self loadItemStatus:playerItemLoad_Fail totalTime:0.0];
            break;
        case AVPlayerStatusUnknown:
            [self loadItemStatus:playerItemLoad_UnknowItem totalTime:0.0];
            break;
        default:
            break;
    }
}

#pragma mark - 加载视频资源成功
- (void)loadVideoResourceSuccess {
    // 修改playerLayer的尺寸，去除黑边，并把视频居中
    CGSize videoSize = [self getVideoSize];
    float width = self.frame.size.width;
    float height = self.frame.size.width*videoSize.height/videoSize.width;
    float x = (self.frame.size.width - width)/2.0;
    float y = (self.frame.size.height - height)/2.0;
    _playerLayer.frame = CGRectMake(x, y, width, height);
    // 开始监听播放的进度
    // 监听播放进度
    __weak typeof(self) weakSelf = self;
    _progressObserver = [_avplayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        [weakSelf videoPlayTime:[weakSelf translateCurrentPlayProgress]];
    }];
    if (_configuration.isAutoPlay) {
        // 如果自动播放，则播放视频
        [self play];
    } else {
        // 如果不自动播放，则展示指定的图片
        self.placeholderImgView.frame = _playerLayer.frame;
        self.placeholderImgView.image = [self thumbnailImageForVideoWithTime:_configuration.placeholderImgTime];
        self.placeholderImgView.hidden = NO;
    }
}

#pragma mark - 视频播放过程中，缓冲不足以继续播放
- (void)playbackStalledAction {
    NSLog(@"缓冲不足以继续播放，播放暂停");
}

#pragma mark - 视频播放结束Action
- (void)playCompleteAction {
    NSLog(@"视频播放结束");
    [self playStatus:play_End];
}

#pragma mark - 监听播放和暂停状态
- (void)playOrPause:(int)rate {
    if (rate == 0) {
        [self playStatus:play_Pause];
    } else if (rate == 1) {
        [self playStatus:play_Play];
    } else {
        NSLog(@"播放其他情况%d",rate);
    }
}

#pragma mark - 从指定位置开始播放视频
- (void)seekToTime:(NSTimeInterval)time {
    if (_avplayer.currentItem.status == AVPlayerStatusReadyToPlay) {
        float targetTime = _avplayer.currentItem.duration.value > time*_avplayer.currentItem.duration.timescale ? time*_avplayer.currentItem.duration.timescale : _avplayer.currentItem.duration.value;
        [_avplayer seekToTime:CMTimeMake(targetTime, _avplayer.currentItem.duration.timescale)];
    } else {
        _seekTime = time;
    }
}

#pragma mark - 获取视频的尺寸
- (CGSize)getVideoSize {
    NSArray *array = _avplayer.currentItem.asset.tracks;
    CGSize videoSize = CGSizeZero;
    for (AVAssetTrack *track in array) {
        if ([track.mediaType isEqualToString:AVMediaTypeVideo]) {
            videoSize = track.naturalSize;
        }
    }
    return videoSize;
}

#pragma mark - 获取指定帧视频截图
- (UIImage*)thumbnailImageForVideoWithTime:(NSTimeInterval)time {
    time = time!=0?time:1;
    AVAssetImageGenerator *assetImageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:_avplayer.currentItem.asset];
    assetImageGenerator.appliesPreferredTrackTransform = YES;
    assetImageGenerator.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;
    CGImageRef thumbnailImageRef = NULL;
    CFTimeInterval thumbnailImageTime = time * _avplayer.currentItem.duration.timescale;
    NSError *thumbnailImageGenerationError = nil;
    thumbnailImageRef = [assetImageGenerator copyCGImageAtTime:CMTimeMake(thumbnailImageTime, _avplayer.currentItem.duration.timescale) actualTime:NULL error:&thumbnailImageGenerationError];
    if (!thumbnailImageRef) {
        return nil;
    }
    UIImage *thumbnailImage = thumbnailImageRef ? [[UIImage alloc]initWithCGImage: thumbnailImageRef] : nil;
    return thumbnailImage;
}

#pragma mark - 获取视频缓冲
- (NSTimeInterval)availableLoadedTime {
    NSArray *loadedTimeRanges = [_avplayer.currentItem loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    NSTimeInterval result = startSeconds + durationSeconds;
    return result;
}

#pragma mark - 当前播放进度转为秒
- (float)translateCurrentPlayProgress {
    return (float)_avplayer.currentTime.value/_avplayer.currentTime.timescale;
}

#pragma mark - 加载资源状态的代理
- (void)loadItemStatus:(PlayerItemLoadStatus)status totalTime:(float)time {
    if (self.delegate && [self.delegate respondsToSelector:@selector(ZHBaseAVplayerView:loadPlayerItemWithStatus:videoTotalTime:)]) {
        [self.delegate ZHBaseAVplayerView:self loadPlayerItemWithStatus:status videoTotalTime:time];
    }
}

#pragma mark - 视频播放状态的代理
- (void)playStatus:(PlayerPlayStatus)status {
    if (self.delegate && [self.delegate respondsToSelector:@selector(ZHBaseAVplayerView:playStatus:)]) {
        [self.delegate ZHBaseAVplayerView:self playStatus:status];
    }
}

#pragma mark - 视频缓冲时间的代理
- (void)videoBufferTime:(float)time {
    if (self.delegate && [self.delegate respondsToSelector:@selector(ZHBaseAVplayerView:videoBufferTime:)]) {
        [self.delegate ZHBaseAVplayerView:self videoBufferTime:time];
    }
}

#pragma mark - 视频播放时间的代理
- (void)videoPlayTime:(float)time {
    if (_seekTime > 0) {
        [self seekToTime:_seekTime];
        _seekTime = 0;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(ZHBaseAVplayerView:videoPlayTime:)]) {
        [self.delegate ZHBaseAVplayerView:self videoPlayTime:time];
    }
}

#pragma mark - 视频播放结束的代理

#pragma mark - ---------- 网络请求 ----------

#pragma mark - ---------- 代理方法 ----------

#pragma mark - ---------- setter/getter ----------
#pragma mark - 占位图
- (UIImageView *)placeholderImgView {
    if (!_placeholderImgView) {
        _placeholderImgView = [[UIImageView alloc] initWithFrame:_playerLayer.bounds];
        _placeholderImgView.userInteractionEnabled = YES;
        _placeholderImgView.contentMode = UIViewContentModeScaleAspectFill;
        [self addSubview:_placeholderImgView];
    }
    return _placeholderImgView;
}
@end
